#ifndef __M_FMT_H__
#define __M_FMT_H__

#include "util.hpp"
#include "message.hpp"
#include "level.hpp"
#include <memory>
#include <vector>
#include <tuple>
#include <ctime>


namespace dhylog
{
    class  FormatItem
    {
        public:
        using ptr=std::shared_ptr<FormatItem>;
        virtual void format(std::ostream &out, const LogMsg &msg) = 0;
    };
    class  MsgFormatItem :public FormatItem
    {
        public:
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<msg._payload;
        }
    };
    class LevelFormatItem :public FormatItem
    {
        public:
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<loglevel::toString(msg._level);
        }
    };
    class TimeFormatItem :public FormatItem
    {
        public:
        TimeFormatItem(const std::string& fmt="%H:%M:%S"):_time_fmt(fmt){}
        void format(std::ostream &out, const LogMsg &msg)override
        {
            struct tm t;
            localtime_r(&msg._ctime,&t);
            char tmp[128];
            strftime(tmp,127,_time_fmt.c_str(),&t);
            out<<tmp;
        }
        private:
        std::string _time_fmt;
   
    };
    class FileFormatItem :public FormatItem
    {
        public:
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<msg._file;
        }
    };
    class LineFormatItem :public FormatItem
    {
        public:
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<msg._line;
        }
    };
    class ThreadFormatItem :public FormatItem
    {
        public:
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<msg._tid;
        }
    };
    class LoggerFormatItem :public FormatItem
    {
        public:
       
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<msg._logger;
        }
    };
    class TabFormatItem :public FormatItem
    {
        public:
       
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<"\t";
        }
    };
    class NlineFormatItem :public FormatItem
    {
        public:
       
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<"\n";
        }
    };
    class OtherFormatItem :public FormatItem
    {
        public:
        OtherFormatItem(const std::string& str="" ):_str(str){}
        void format(std::ostream &out, const LogMsg &msg)override
        {
            out<<_str;
        }
        private:
        std::string _str;
    };
    class Formatter
    {
        public:
        using ptr=std::shared_ptr<Formatter>;
           /*
            %d 日期
            %T 缩进
            %t 线程id
            %p 日志级别
            %c 日志器名称
            %f 文件名
            %l 行号
            %m 日志消息
            %n 换行
        */
        //时间{年-月-日 时:分:秒}缩进 线程ID 缩进 [日志级别] 缩进 [日志名称] 缩进 文件名:行号 缩进 消息换行 [%d{%H:%M:%S}][%t][%p][%c][%f:%l]%m%n
        Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l]%m%n"):_pattern(pattern)
        {
            assert(parsePattern());
        }
        const std::string pattern() { return _pattern; }
        std::string format(const LogMsg &msg)
        {
            std::stringstream ss;
            for(auto &it :_items)
            {
                it->format(ss,msg);
            }
            return ss.str();
        }
        std::ostream& format(std::ostream &out,const LogMsg&msg)
        {
            for(auto &it :_items)
            {
                it->format(out,msg);
            }
            return out;
        }
        
        FormatItem::ptr createItem(const std::string &key, const std::string &val) 
        {
            if(key=="d") return std::make_shared<TimeFormatItem>(val);
            if(key=="T") return std::make_shared<TabFormatItem>();
            if(key=="c") return std::make_shared<LoggerFormatItem>();
            if(key=="f") return std::make_shared<FileFormatItem>();
            if(key=="l") return std::make_shared<LineFormatItem>();
            if(key=="p") return std::make_shared<LevelFormatItem>();
            if(key=="t") return std::make_shared<ThreadFormatItem>();
            if(key=="m") return std::make_shared<MsgFormatItem>();
            if(key=="n") return std::make_shared<NlineFormatItem>();
            if(key.empty()) return std::make_shared<OtherFormatItem>(val);
            std::cout<<"没有对应的格式化字符%"<<key<<std::endl;
            abort();
        }
        private:
        bool parsePattern() 
        {
            //[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n
            //sg{}fsg%d{%H:%M:%S}%Tsdf%t%T[%p]%T[%c]%T%f:%l%T%m%n 
            std::vector<std::pair<std::string,std::string>> fmt_order;
            size_t pos=0;
            std::string key,value;
            while(pos<_pattern.size())
            {
                //寻找%
                if(_pattern[pos]!='%')  
                {
                    value.push_back(_pattern[pos++]);
                    continue;
                }
                //当前位置为%,判断后面是否为%
                if(pos+1<_pattern.size()&&_pattern[pos+1]=='%'){value.push_back('%');pos+=2;continue;};
                //当前位置为%,且pos+1不为%,剔除前两下项为%d的情况
                if(!value.empty())
                {
                    fmt_order.push_back(std::make_pair("",value));
                    value.clear();
                }
                //当前位置为%，后面为格式化字符，接下来处理格式化字符
                pos+=1;//当前位置为格式化字符，判断越界
                if(pos==_pattern.size())
                {
                    std::cout<<"%之后，没有对相应的格式化字符!\n";
                    return false;
                }
                key=_pattern[pos];
                pos+=1;
                //格式化字符完整，当前位置为格式化字符后一位，判断是否为{
                if(pos<_pattern.size()&&_pattern[pos]=='{')
                {
                    pos++;
                    while(pos<_pattern.size()&&_pattern[pos]!='}')
                    {
                        value.push_back(_pattern[pos++]);
                    }
                    if(pos==_pattern.size())
                    {
                        std::cout<<"{不匹配";
                        return false;
                    }
                    pos+=1;
                }    
                fmt_order.push_back(std::make_pair(key,value));
                key.clear();
                value.clear();
            }
            for(auto &it:fmt_order)
            {
                _items.push_back(createItem(it.first,it.second));
            }
            return true;
        }
        std::string _pattern;
        std::vector<FormatItem::ptr> _items;
    };
}

#endif